home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Environments
/
PowerLisp 2.01
/
Supplemental Documentation
/
Documentation
/
Chapter 08. Macros
< prev
next >
Wrap
Text File
|
1995-03-27
|
50KB
|
1,103 lines
Common Lisp the Language, 2nd Edition
-------------------------------------------------------------------------------
8. Macros
The Common Lisp macro facility allows the user to define arbitrary functions
that convert certain Lisp forms into different forms before evaluating or
compiling them. This is done at the expression level, not at the
character-string level as in most other languages. Macros are important in the
writing of good code: they make it possible to write code that is clear and
elegant at the user level but that is converted to a more complex or more
efficient internal form for execution.
When eval is given a list whose car is a symbol, it looks for local definitions
of that symbol (by flet, labels, and macrolet); if that fails, it looks for a
global definition. If the definition is a macro definition, then the original
list is said to be a macro call. Associated with the definition will be a
function of two arguments, called the expansion function. This function is
called with the entire macro call as its first argument (the second argument is
a lexical environment); it must return some new Lisp form, called the expansion
of the macro call. (Actually, a more general mechanism is involved; see
macroexpand.) This expansion is then evaluated in place of the original form.
When a function is being compiled, any macros it contains are expanded at
compilation time. This means that a macro definition must be seen by the
compiler before the first use of the macro.
More generally, an implementation of Common Lisp has great latitude in deciding
exactly when to expand macro calls within a program. For example, it is
acceptable for the defun special form to expand all macro calls within its body
at the time the defun form is executed and record the fully expanded body as
the body of the function being defined. (An implementation might even choose
always to compile functions defined by defun, even when operating in an
``interpretive'' mode.)
Macros should be written so as to depend as little as possible on the execution
environment to produce a correct expansion. To ensure consistent behavior, it
is best to ensure that all macro definitions are available, whether to the
interpreter or compiler, before any code containing calls to those macros is
introduced.
In Common Lisp, macros are not functions. In particular, macros cannot be used
as functional arguments to such functions as apply, funcall, or map; in such
situations, the list representing the ``original macro call'' does not exist,
and cannot exist, because in some sense the arguments have already been
evaluated.
-------------------------------------------------------------------------------
* Macro Definition
* Macro Expansion
* Destructuring
* Compiler Macros
* Environments
-------------------------------------------------------------------------------
8.1. Macro Definition
The function macro-function determines whether a given symbol is the name of a
macro. The defmacro construct provides a convenient way to define new macros.
[old_change_begin]
[Function]
macro-function symbol
The argument must be a symbol. If the symbol has a global function definition
that is a macro definition, then the expansion function (a function of two
arguments, the macro-call form and an environment) is returned. If the symbol
has no global function definition, or has a definition as an ordinary function
or as a special form but not as a macro, then nil is returned. The function
macroexpand is the best way to invoke the expansion function.
It is possible for both macro-function and special-form-p to be true of a
symbol. This is possible because an implementation is permitted to implement
any macro also as a special form for speed. On the other hand, the macro
definition must be available for use by programs that understand only the
standard special forms listed in table 5-1.
macro-function cannot be used to determine whether a symbol names a locally
defined macro established by macrolet; macro-function can examine only global
definitions.
setf may be used with macro-function to install a macro as a symbol's global
function definition:
(setf (macro-function symbol) fn)
The value installed must be a function that accepts two arguments, an entire
macro call and an environment, and computes the expansion for that call.
Performing this operation causes the symbol to have only that macro definition
as its global function definition; any previous definition, whether as a macro
or as a function, is lost. It is an error to attempt to redefine the name of a
special form.
[old_change_end]
[change_begin]
X3J13 voted in March 1988 (MACRO-FUNCTION-ENVIRONMENT) to add an optional
environment argument to macro-function.
[Function]
macro-function symbol &optional env
The first argument must be a symbol. If the symbol has a function definition
that is a macro definition, whether a local one established in the environment
env by macrolet or a global one established as if by defmacro, then the
expansion function (a function of two arguments, the macro-call form and an
environment) is returned. If the symbol has no function definition, or has a
definition as an ordinary function or as a special form but not as a macro,
then nil is returned. The function macroexpand or macroexpand-1 is the best way
to invoke the expansion function.
It is possible for both macro-function and special-form-p to be true of a
symbol. This is possible because an implementation is permitted to implement
any macro also as a special form for speed. On the other hand, the macro
definition must be available for use by programs that understand only the
standard special forms listed in table 5-1.
setf may be used with macro-function to install a macro as a symbol's global
function definition:
(setf (macro-function symbol) fn)
The value installed must be a function that accepts two arguments, an entire
macro call and an environment, and computes the expansion for that call.
Performing this operation causes the symbol to have only that macro definition
as its global function definition; any previous definition, whether as a macro
or as a function, is lost. One cannot use setf to establish a local macro
definition; it is an error to supply a second argument to macro-function when
using it with setf. It is an error to attempt to redefine the name of a special
form.
See also compiler-macro-function.
[change_end]
[Macro]
defmacro name lambda-list [[ {declaration}* | doc-string ]] {form}*
defmacro is a macro-defining macro that arranges to decompose the macro-call
form in an elegant and useful way. defmacro has essentially the same syntax as
defun: name is the symbol whose macro definition we are creating, lambda-list
is similar in form to a lambda-list, and the forms constitute the body of the
expander function. The defmacro construct arranges to install this expander
function, as the global macro definition of name.
[old_change_begin]
The expander function is effectively defined in the global environment;
lexically scoped entities established outside the defmacro form that would
ordinarily be lexically apparent are not visible within the body of the
expansion function.
[old_change_end]
[change_begin]
X3J13 voted in March 1989 (DEFINING-MACROS-NON-TOP-LEVEL) to clarify that,
while defining forms normally appear at top level, it is meaningful to place
them in non-top-level contexts. Furthermore, defmacro should define the
expander function within the enclosing lexical environment, not within the
global environment.
X3J13 voted in March 1988 (FLET-IMPLICIT-BLOCK) to specify that the body of
the expander function defined by defmacro is implicitly enclosed in a block
construct whose name is the same as the name of the defined macro. Therefore
return-from may be used to exit from the function.
[change_end]
The name is returned as the value of the defmacro form.
If we view the macro call as a list containing a function name and some
argument forms, in effect the expander function and the list of (unevaluated)
argument forms is given to apply. The parameter specifiers are processed as for
any lambda-expression, using the macro-call argument forms as the arguments.
Then the body forms are evaluated as an implicit progn, and the value of the
last form is returned as the expansion of the macro call.
If the optional documentation string doc-string is present (if not followed by
a declaration, it may be present only if at least one form is also specified,
as it is otherwise taken to be a form), then it is attached to the name as a
documentation string of type function; see documentation.
[old_change_begin]
Like the lambda-list in a defun, a defmacro lambda-list may contain the
lambda-list keywords &optional, &rest, &key, &allow-other-keys, and &aux. For
&optional and &key parameters, initialization forms and supplied-p parameters
may be specified, just as for defun. Three additional markers are allowed in
defmacro variable lists only.
[old_change_end]
[change_begin]
These three markers are now allowed in other constructs as well.
[change_end]
&body
This is identical in function to &rest, but it informs certain
output-formatting and editing functions that the remainder of the form is
treated as a body and should be indented accordingly. (Only one of &body
or &rest may be used.)
&whole
This is followed by a single variable that is bound to the entire
macro-call form; this is the value that the macro definition function
receives as its single argument. &whole and the following variable should
appear first in the lambda-list, before any other parameter or lambda-list
keyword.
&environment
This is followed by a single variable that is bound to an environment
representing the lexical environment in which the macro call is to be
interpreted. This environment may not be the complete lexical environment;
it should be used only with the function macroexpand for the sake of any
local macro definitions that the macrolet construct may have established
within that lexical environment. This is useful primarily in the rare
cases where a macro definition must explicitly expand any macros in a
subform of the macro call before computing its own expansion.
See lambda-list-keywords.
[change_begin]
Notice of correction. In the first edition, the symbol &environment at the left
margin above was inadvertently omitted.
X3J13 voted in March 1989 (MACRO-ENVIRONMENT-EXTENT) to specify that macro
environment objects received with the &environment argument of a macro function
have only dynamic extent. The consequences are undefined if such objects are
referred to outside the dynamic extent of that particular invocation of the
macro function. This allows implementations to use somewhat more efficient
techniques for representing environment objects.
X3J13 voted in March 1989 (DEFMACRO-LAMBDA-LIST) to clarify the permitted
uses of &body, &whole, and &environment:
* &body may appear at any level of a defmacro lambda-list.
* &whole may appear at any level of a defmacro lambda-list. At inner levels
a &whole variable is bound to that part of the argument that matches the
sub-lambda-list in which &whole appears. No matter where &whole is used,
other parameters or lambda-list keywords may follow it.
* &environment may occur only at the outermost level of a defmacro
lambda-list, and it may occur at most once, but it may occur anywhere
within that lambda-list, even before an occurrence of &whole.
[change_end]
defmacro, unlike any other Common Lisp construct that has a lambda-list as part
of its syntax, provides an additional facility known as destructuring.
[change_begin]
See destructuring-bind, which provides the destructuring facility separately.
[change_end]
Anywhere in the lambda-list where a parameter name may appear, and where
ordinary lambda-list syntax (as described in section 5.2.2) does not otherwise
allow a list, a lambda-list may appear in place of the parameter name. When
this is done, then the argument form that would match the parameter is treated
as a (possibly dotted) list, to be used as an argument forms list for
satisfying the parameters in the embedded lambda-list. As an example, one could
write the macro definition for dolist in this manner:
(defmacro dolist ((var listform &optional resultform)
&rest body)
...)
More examples of embedded lambda-lists in defmacro are shown below.
Another destructuring rule is that defmacro allows any lambda-list (whether
top-level or embedded) to be dotted, ending in a parameter name. This situation
is treated exactly as if the parameter name that ends the list had appeared
preceded by &rest. For example, the definition skeleton for dolist shown above
could instead have been written
(defmacro dolist ((var listform &optional resultform)
. body)
...)
If the compiler encounters a defmacro, the new macro is added to the
compilation environment, and a compiled form of the expansion function is also
added to the output file so that the new macro will be operative at run time.
If this is not the desired effect, the defmacro form can be wrapped in an
eval-when construct.
It is permissible to use defmacro to redefine a macro (for example, to install
a corrected version of an incorrect definition), or to redefine a function as a
macro. It is an error to attempt to redefine the name of a special form (see
table 5-1) as a macro. See macrolet, which establishes macro definitions over a
restricted lexical scope.
[change_begin]
See also define-compiler-macro.
[change_end]
Suppose, for the sake of example, that it were desirable to implement a
conditional construct analogous to the Fortran arithmetic IF statement. (This
of course requires a certain stretching of the imagination and suspension of
disbelief.) The construct should accept four forms: a test-value, a neg-form, a
zero-form, and a pos-form. One of the last three forms is chosen to be executed
according to whether the value of the test-form is positive, negative, or zero.
Using defmacro, a definition for such a construct might look like this:
(defmacro arithmetic-if (test neg-form zero-form pos-form)
(let ((var (gensym)))
`(let ((,var ,test))
(cond ((< ,var 0) ,neg-form)
((= ,var 0) ,zero-form)
(t ,pos-form)))))
Note the use of the backquote facility in this definition (see section 22.1.3).
Also note the use of gensym to generate a new variable name. This is necessary
to avoid conflict with any variables that might be referred to in neg-form,
zero-form, or pos-form.
If the form is executed by the interpreter, it will cause the function
definition of the symbol arithmetic-if to be a macro associated with which is a
two-argument expansion function roughly equivalent to
(lambda (calling-form environment)
(declare (ignore environment))
(let ((var (gensym)))
(list 'let
(list (list 'var (cadr calling-form)))
(list 'cond
(list (list '< var '0) (caddr calling-form))
(list (list '= var '0) (cadddr calling-form))
(list 't (fifth calling-form))))))
The lambda-expression is produced by the defmacro declaration. The calls to
list are the (hypothetical) result of the backquote (`) macro character and its
associated commas. The precise macro expansion function may depend on the
implementation, for example providing some degree of explicit error checking on
the number of argument forms in the macro call.
Now, if eval encounters
(arithmetic-if (- x 4.0)
(- x)
(error "Strange zero")
x)
this will be expanded into something like
(let ((g407 (- x 4.0)))
(cond ((< g407 0) (- x))
((= g407 0) (error "Strange zero"))
(t x)))
and eval tries again on this new form. (It should be clear now that the
backquote facility is very useful in writing macros, since the form to be
returned is normally a complex list structure, typically consisting of a mostly
constant template with a few evaluated forms here and there. The backquote
template provides a ``picture'' of the resulting code, with places to be filled
in indicated by preceding commas.)
To expand on this example, stretching credibility to its limit, we might allow
the pos-form and zero-form to be omitted, allowing their values to default to
nil, in much the same way that the else form of a Common Lisp if construct may
be omitted:
(defmacro arithmetic-if (test neg-form
&optional zero-form pos-form)
(let ((var (gensym)))
`(let ((,var ,test))
(cond ((< ,var 0) ,neg-form)
((= ,var 0) ,zero-form)
(t ,pos-form)))))
Then one could write
(arithmetic-if (- x 4.0) (print x))
which would be expanded into something like
(let ((g408 (- x 4.0)))
(cond ((< g408 0) (print x))
((= g408 0) nil)
(t nil)))
The resulting code is correct but rather silly-looking. One might rewrite the
macro definition to produce better code when pos-form and possibly zero-form
are omitted, or one might simply rely on the Common Lisp implementation to
provide a compiler smart enough to improve the code itself.
Destructuring is a very powerful facility that allows the defmacro lambda-list
to express the structure of a complicated macro-call syntax. If no lambda-list
keywords appear, then the defmacro lambda-list is simply a list, nested to some
extent, containing parameter names at the leaves. The macro-call form must have
the same list structure. For example, consider this macro definition:
(defmacro halibut ((mouth eye1 eye2)
((fin1 length1) (fin2 length2))
tail)
...)
Now consider this macro call:
(halibut (m (car eyes) (cdr eyes))
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
This would cause the expansion function to receive the following values for its
parameters:
Parameter Value
---------------------------------
mouth m
eye1 (car eyes)
eye2 (cdr eyes)
fin1 f1
length1 (count-scales f1)
fin2 f2
length2 (count-scales f2)
tail my-favorite-tail
---------------------------------
The following macro call would be in error because there would be no argument
form to match the parameter length1:
(halibut (m (car eyes) (cdr eyes))
((f1) (f2 (count-scales f2)))
my-favorite-tail)
The following macro call would be in error because a symbol appears in the call
where the structure of the lambda-list requires a list.
(halibut my-favorite-head
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
The fact that the value of the variable my-favorite-head might happen to be a
list is irrelevant here. It is the macro call itself whose structure must match
that of the defmacro lambda-list.
The use of lambda-list keywords adds even greater flexibility. For example,
suppose it is convenient within the expansion function for halibut to be able
to refer to the list whose components are called mouth, eye1, and eye2 as head.
One may write this:
(defmacro halibut ((&whole head mouth eye1 eye2)
((fin1 length1) (fin2 length2))
tail)
Now consider the same valid macro call as before:
(halibut (m (car eyes) (cdr eyes))
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
This would cause the expansion function to receive the same values for its
parameters and also a value for the parameter head:
Parameter Value
------------------------------------------
head (m (car eyes) (cdr eyes))
------------------------------------------
The stipulation that an embedded lambda-list is permitted only where ordinary
lambda-list syntax would permit a parameter name but not a list is made to
prevent ambiguity. For example, one may not write
(defmacro loser (x &optional (a b &rest c) &rest z)
...)
because ordinary lambda-list syntax does permit a list following &optional; the
list (a b &rest c) would be interpreted as describing an optional parameter
named a whose default value is that of the form b, with a supplied-p parameter
named &rest (not legal), and an extraneous symbol c in the list (also not
legal). An almost correct way to express this is
(defmacro loser (x &optional ((a b &rest c)) &rest z)
...)
The extra set of parentheses removes the ambiguity. However, the definition is
now incorrect because a macro call such as (loser (car pool)) would not provide
any argument form for the lambda-list (a b &rest c), and so the default value
against which to match the lambda-list would be nil because no explicit default
value was specified. This is in error because nil is an empty list; it does not
have forms to satisfy the parameters a and b. The fully correct definition
would be either
(defmacro loser (x &optional ((a b &rest c) '(nil nil)) &rest z)
...)
or
(defmacro loser (x &optional ((&optional a b &rest c)) &rest z)
...)
These differ slightly: the first requires that if the macro call specifies a
explicitly then it must also specify b explicitly, whereas the second does not
have this requirement. For example,
(loser (car pool) ((+ x 1)))
would be a valid call for the second definition but not for the first.
-------------------------------------------------------------------------------
8.2. Macro Expansion
The macroexpand function is the conventional means for expanding a macro call.
A hook is provided for a user function to gain control during the expansion
process.
[Function]
macroexpand form &optional env
macroexpand-1 form &optional env
If form is a macro call, then macroexpand-1 will expand the macro call once and
return two values: the expansion and t. If form is not a macro call, then the
two values form and nil are returned.
A form is considered to be a macro call only if it is a cons whose car is a
symbol that names a macro. The environment env is similar to that used within
the evaluator (see evalhook); it defaults to a null environment. Any local
macro definitions established within env by macrolet will be considered. If
only form is given as an argument, then the environment is effectively null,
and only global macro definitions (as established by defmacro) will be
considered.
Macro expansion is carried out as follows. Once macroexpand-1 has determined
that a symbol names a macro, it obtains the expansion function for that macro.
The value of the variable *macroexpand-hook* is then called as a function of
three arguments: the expansion function, the form, and the environment env. The
value returned from this call is taken to be the expansion of the macro call.
The initial value of *macroexpand-hook* is funcall, and the net effect is to
invoke the expansion function, giving it form and env as its two arguments.
[change_begin]
X3J13 voted in June 1988 (FUNCTION-TYPE) to specify that the value of
*macroexpand-hook* is first coerced to a function before being called as the
expansion interface hook. Therefore its value may be a symbol, a
lambda-expression, or any object of type function.
X3J13 voted in March 1989 (MACRO-ENVIRONMENT-EXTENT) to specify that macro
environment objects received by a *macroexpand-hook* function have only dynamic
extent. The consequences are undefined if such objects are referred to outside
the dynamic extent of that particular invocation of the hook function. This
allows implementations to use somewhat more efficient techniques for
representing environment objects.
[change_end]
[old_change_begin]
(The purpose of *macroexpand-hook* is to facilitate various techniques for
improving interpretation speed by caching macro expansions.)
[old_change_end]
[change_begin]
X3J13 voted in June 1989 (MACRO-CACHING) to clarify that, while
*macroexpand-hook* may be useful for debugging purposes, despite the original
design intent there is currently no correct portable way to use it for caching
macro expansions.
* Caching by displacement (performing a side effect on the macro-call form)
won't work because the same (eq) macro-call form may appear in distinct
lexical contexts. In addition, the macro-call form may be a read-only
constant (see quote and also section 25.1).
* Caching by table lookup won't work because such a table would have to be
keyed by both the macro-call form and the environment, but X3J13 voted in
March 1989 (MACRO-ENVIRONMENT-EXTENT) to permit macro environments to
have only dynamic extent.
* Caching by storing macro-call forms and expansions within the environment
object itself would work, but there are no portable primitives that would
allow users to do this.
X3J13 also noted that, although there seems to be no correct portable way to
use *macroexpand-hook* to cache macro expansions, there is no requirement that
an implementation call the macro expansion function more than once for a given
form and lexical environment.
X3J13 voted in March 1989 (SYMBOL-MACROLET-SEMANTICS) to specify that
macroexpand-1 will also expand symbol macros defined by symbol-macrolet;
therefore a form may also be a macro call if it is a symbol. The vote did not
address the interaction of this feature with the *macroexpand-hook* function.
An obvious implementation choice is that the hook function is indeed called and
given a special expansion function that, when applied to the form (a symbol)
and env, will produce the expansion, just as for an ordinary macro; but this is
only my suggestion.
[change_end]
The evaluator expands macro calls as if through the use of macroexpand-1; the
point is that eval also uses *macroexpand-hook*.
macroexpand is similar to macroexpand-1, but repeatedly expands form until it
is no longer a macro call. (In effect, macroexpand simply calls macroexpand-1
repeatedly until the second value returned is nil.) A second value of t or nil
is returned as for macroexpand-1, indicating whether the original form was a
macro call.
[Variable]
*macroexpand-hook*
The value of *macroexpand-hook* is used as the expansion interface hook by
macroexpand-1.
-------------------------------------------------------------------------------
8.3. Destructuring
[change_begin]
X3J13 voted in March 1989 (DESTRUCTURING-BIND) to make the destructuring
feature of defmacro available as a separate facility.
[Macro]
destructuring-bind lambda-list expression {declaration}* {form}*
This macro binds the variables specified in lambda-list to the corresponding
values in the tree structure resulting from evaluating the expression, then
executes the forms as an implicit progn.
A destructuring-bind lambda-list may contain the lambda-list keywords
&optional, &rest, &key, &allow-other-keys, and &aux; &body and &whole may also
be used as they are in defmacro, but &environment may not be used. Nested and
dotted lambda-lists are also permitted as for defmacro. The idea is that a
destructuring-bind lambda-list has the same format as inner levels of a
defmacro lambda-list.
If the result of evaluating the expression does not match the destructuring
pattern, an error should be signaled.
[change_end]
-------------------------------------------------------------------------------
8.4. Compiler Macros
[change_begin]
X3J13 voted in June 1989 (DEFINE-COMPILER-MACRO) to add a facility for
defining compiler macros that take effect only when compiling code, not when
interpreting it.
The purpose of this facility is to permit selective source-code transformations
only when the compiler is processing the code. When the compiler is about to
compile a non-atomic form, it first calls compiler-macroexpand-1 repeatedly
until there is no more expansion (there might not be any to begin with). Then
it continues its remaining processing, which may include calling macroexpand-1
and so on.
The compiler is required to expand compiler macros. It is unspecified whether
the interpreter does so. The intention is that only the compiler will do so,
but the range of possible ``compiled-only'' implementation strategies precludes
any firm specification.
[Macro]
define-compiler-macro name lambda-list {declaration | doc-string}* {form}*
This is just like defmacro except the definition is not stored in the symbol
function cell of name and is not seen by macroexpand-1. It is, however, seen by
compiler-macroexpand-1. As with defmacro, the lambda-list may include
&environment and &whole and may include destructuring. The definition is
global. (There is no provision for defining local compiler macros in the way
that macrolet defines local macros.)
A top-level call to define-compiler-macro in a file being compiled by
compile-file has an effect on the compilation environment similar to that of a
call to defmacro, except it is noticed as a compiler macro (see section 25.1).
Note that compiler macro definitions do not appear in information returned by
function-information; they are global, and their interaction with other lexical
and global definitions can be reconstructed by compiler-macro-function. It is
up to code-walking programs to decide whether to invoke compiler macro
expansion.
X3J13 voted in March 1988 (FLET-IMPLICIT-BLOCK) to specify that the body of
the expander function defined by defmacro is implicitly enclosed in a block
construct whose name is the same as the name of the defined macro; presumably
this applies also to define-compiler-macro. Therefore return-from may be used
to exit from the function.
[Function]
compiler-macro-function name &optional env
The name must be a symbol. If it has been defined as a compiler macro, then
compiler-macro-function returns the macro expansion function; otherwise it
returns nil. The lexical environment env may override any global definition for
name by defining a local function or local macro (such as by flet, labels, or
macrolet) in which case nil is returned.
setf may be used with compiler-macro-function to install a function as the
expansion function for the compiler macro name, in the same manner as for
macro-function. Storing the value nil removes any existing compiler macro
definition. As with macro-function, a non-nil stored value must be a function
of two arguments, the entire macro call and the environment. The second
argument to compiler-macro-function must be omitted when it is used with setf.
[Function]
compiler-macroexpand form &optional env
compiler-macroexpand-1 form &optional env
These are just like macroexpand and macroexpand-1 except that the expander
function is obtained as if by a call to compiler-macro-function on the car of
the form rather than by a call to macro-function. Note that
compiler-macroexpand performs repeated expansion but compiler-macroexpand-1
performs at most one expansion. Two values are returned, the expansion (or the
original form) and a value that is true if any expansion occurred and nil
otherwise.
There are three cases where no expansion happens:
* There is no compiler macro definition for the car of form.
* There is such a definition but there is also a notinline declaration,
either globally or in the lexical environment env.
* A global compiler macro definition is shadowed by a local function or
macro definition (such as by flet, labels, or macrolet).
Note that if there is no expansion, the original form is returned as the first
value, and nil as the second value.
Any macro expansion performed by the function compiler-macroexpand or by the
function compiler-macroexpand-1 is carried out by calling the function that is
the value of *macroexpand-hook*.
A compiler macro may decline to provide any expansion merely by returning the
original form. This is useful when using the facility to put ``compiler
optimizers'' on various function names. For example, here is a compiler macro
that ``optimizes'' (one would hope) the zero-argument and one-argument cases of
a function called plus:
(define-compiler-macro plus (&whole form &rest args)
(case (length args)
(0 0)
(1 (car args))
(t form)))
[change_end]
-------------------------------------------------------------------------------
8.5. Environments
[change_begin]
X3J13 voted in June 1989 (SYNTACTIC-ENVIRONMENT-ACCESS) to add some
facilities for obtaining information from environment objects of the kind
received as arguments by macro expansion functions, *macroexpand-hook*
functions, and *evalhook* functions. There is a minimal set of accessors
(variable-information, function-information, and declaration-information) and a
constructor (augment-environment) for environments.
All of the standard declaration specifiers, with the exception of special, can
be defined fairly easily using define-declaration. It also seems to be able to
handle most extended declarations.
The function parse-macro is provided so that users don't have to write their
own code to destructure macro arguments. This function is not entirely
necessary since X3J13 voted in March 1989 (DESTRUCTURING-BIND) to add
destructuring-bind to the language. However, parse-macro is worth having
anyway, since any program-analyzing program is going to need to define it, and
the implementation isn't completely trivial even with destructuring-bind to
build upon.
The function enclose allows expander functions to be defined in a non-null
lexical environment, as required by the vote of X3J13 in March 1989
(DEFINING-MACROS-NON-TOP-LEVEL) . It also provides a mechanism by which a
program processing the body of an (eval-when (:compile-toplevel) ...) form can
execute it in the enclosing environment (see issue (EVAL-WHEN-NON-TOP-LEVEL)
).
In all of these functions the argument named env is an environment object. (It
is not required that implementations provide a distinguished representation for
such objects.) Optional env arguments default to nil, which represents the
local null lexical environment (containing only global definitions and
proclamations that are present in the run-time environment). All of these
functions should signal an error of type type-error if the value of an
environment argument is not a syntactic environment object.
The accessor functions variable-information, function-information, and
declaration-information retrieve information about declarations that are in
effect in the environment. Since implementations are permitted to ignore
declarations (except for special declarations and optimize safety declarations
if they ever compile unsafe code), these accessors are required only to return
information about declarations that were explicitly added to the environment
using augment-environment. They might also return information about
declarations recognized and added to the environment by the interpreter or the
compiler, but that is at the discretion of the implementor. Implementations are
also permitted to canonicalize declarations, so the information returned by the
accessors might not be identical to the information that was passed to
augment-environment.
[Function]
variable-information variable &optional env
This function returns information about the interpretation of the symbol
variable when it appears as a variable within the lexical environment env.
Three values are returned.
The first value indicates the type of definition or binding for variable in
env:
nil There is no apparent definition or binding for variable.
:special
The variable refers to a special variable, either declared or proclaimed.
:lexical
The variable refers to a lexical variable.
:symbol-macro
The variable refers to a symbol-macrolet binding.
:constant
Either the variable refers to a named constant defined by defconstant or
the variable is a keyword symbol.
The second value indicates whether there is a local binding of the name. If the
name is locally bound, the second value is true; otherwise, the second value is
nil.
The third value is an a-list containing information about declarations that
apply to the apparent binding of the variable. The keys in the a-list are
symbols that name declaration specifiers, and the format of the corresponding
value in the cdr of each pair depends on the particular declaration name
involved. The standard declaration names that might appear as keys in this
a-list are:
dynamic-extent
A non-nil value indicates that the variable has been declared
dynamic-extent. If the value is nil, the pair might be omitted.
ignore
A non-nil value indicates that the variable has been declared ignore. If
the value is nil, the pair might be omitted.
type
The value is a type specifier associated with the variable by a type
declaration or an abbreviated declaration such as (fixnum variable). If no
explicit association exists, either by proclaim or declare, then the type
specifier is t. It is permissible for implementations to use a type
specifier that is equivalent to or a supertype of the one appearing in the
original declaration. If the value is t, the pair might be omitted.
If an implementation supports additional declaration specifiers that apply to
variable bindings, those declaration names might also appear in the a-list.
However, the corresponding key must not be a symbol that is external in any
package defined in the standard or that is otherwise accessible in the
common-lisp-user package.
The a-list might contain multiple entries for a given key. The consequences of
destructively modifying the list structure of this a-list or its elements
(except for values that appear in the a-list as a result of define-declaration)
are undefined.
Note that the global binding might differ from the local one and can be
retrieved by calling variable-information with a null lexical environment.
[Function]
function-information function &optional env
This function returns information about the interpretation of the function-name
function when it appears in a functional position within lexical environment
env. Three values are returned.
The first value indicates the type of definition or binding of the
function-name which is apparent in env:
nil There is no apparent definition for function.
:function
The function refers to a function.
:macro
The function refers to a macro.
:special-form
The function refers to a special form.
Some function-names can refer to both a global macro and a global special form.
In such a case the macro takes precedence and :macro is returned as the first
value.
The second value specifies whether the definition is local or global. If local,
the second value is true; it is nil when the definition is global.
The third value is an a-list containing information about declarations that
apply to the apparent binding of the function. The keys in the a-list are
symbols that name declaration specifiers, and the format of the corresponding
values in the cdr of each pair depends on the particular declaration name
involved. The standard declaration names that might appear as keys in this
a-list are:
dynamic-extent
A non-nil value indicates that the function has been declared
dynamic-extent. If the value is nil, the pair might be omitted.
inline
The value is one of the symbols inline, notinline, or nil to indicate
whether the function-name has been declared inline, declared notinline, or
neither, respectively. If the value is nil, the pair might be omitted.
ftype
The value is the type specifier associated with the function-name in the
environment, or the symbol function if there is no functional type
declaration or proclamation associated with the function-name. This value
might not include all the apparent ftype declarations for the
function-name. It is permissible for implementations to use a type
specifier that is equivalent to or a supertype of the one that appeared in
the original declaration. If the value is function, the pair might be
omitted.
If an implementation supports additional declaration specifiers that apply to
function bindings, those declaration names might also appear in the a-list.
However, the corresponding key must not be a symbol that is external in any
package defined in the standard or that is otherwise accessible in the
common-lisp-user package.
The a-list might contain multiple entries for a given key. In this case the
value associated with the first entry has precedence. The consequences of
destructively modifying the list structure of this a-list or its elements
(except for values that appear in the a-list as a result of define-declaration)
are undefined.
Note that the global binding might differ from the local one and can be
retrieved by calling function-information with a null lexical environment.
[Function]
declaration-information decl-name &optional env
This function returns information about declarations named by the symbol
decl-name that are in force in the environment env. Only declarations that do
not apply to function or variable bindings can be accessed with this function.
The format of the information that is returned depends on the decl-name
involved.
It is required that this function recognize optimize and declaration as
decl-names. The values returned for these two cases are as follows:
optimize
A single value is returned, a list whose entries are of the form (quality
value), where quality is one of the standard optimization qualities
(speed, safety, compilation-speed, space, debug) or some
implementation-specific optimization quality, and value is an integer in
the range 0 to 3 (inclusive). The returned list always contains an entry
for each of the standard qualities and for each of the
implementation-specific qualities. In the absence of any previous
declarations, the associated values are implementation-dependent. The list
might contain multiple entries for a quality, in which case the first such
entry specifies the current value. The consequences of destructively
modifying this list or its elements are undefined.
declaration
A single value is returned, a list of the declaration names that have been
proclaimed as valid through the use of the declaration proclamation. The
consequences of destructively modifying this list or its elements are
undefined.
If an implementation is extended to recognize additional declaration specifiers
in declare or proclaim, it is required that either the declaration-information
function should recognize those declarations also or the implementation should
provide a similar accessor that is specialized for that declaration specifier.
If declaration-information is used to return the information, the corresponding
decl-name must not be a symbol that is external in any package defined in the
standard or that is otherwise accessible in the common-lisp-user package.
[Function]
augment-environment env &key :variable :symbol-macro
:function :macro :declare
This function returns a new environment containing the information present in
env augmented with the information provided by the keyword arguments. It is
intended to be used by program analyzers that perform a code walk.
The arguments are supplied as follows.
:variable
The argument is a list of symbols that will be visible as bound variables
in the new environment. Whether each binding is to be interpreted as
special or lexical depends on special declarations recorded in the
environment or provided in the :declare argument.
:symbol-macro
The argument is a list of symbol macro definitions, each of the form (name
definition); that is, the argument is in the same format as the cadr of a
symbol-macrolet special form. The new environment will have local
symbol-macro bindings of each symbol to the corresponding expansion, so
that macroexpand will be able to expand them properly. A type declaration
in the :declare argument that refers to a name in this list implicitly
modifies the definition associated with the name. The effect is to wrap a
the form mentioning the type around the definition.
:function
The argument is a list of function-names that will be visible as local
function bindings in the new environment.
:macro
The argument is a list of local macro definitions, each of the form (name
definition). Note that the argument is not in the same format as the cadr
of a macrolet special form. Each definition must be a function of two
arguments (a form and an environment). The new environment will have local
macro bindings of each name to the corresponding expander function, which
will be returned by macro-function and used by macroexpand.
:declare
The argument is a list of declaration specifiers. Information about these
declarations can be retrieved from the resulting environment using
variable-information, function-information, and declaration-information.
The consequences of subsequently destructively modifying the list structure of
any of the arguments to this function are undefined.
An error is signaled if any of the symbols naming a symbol macro in the
:symbol-macro argument is also included in the :variable argument. An error is
signaled if any symbol naming a symbol macro in the :symbol-macro argument is
also included in a special declaration specifier in the :declare argument. An
error is signaled if any symbol naming a macro in the :macro argument is also
included in the :function argument. The condition type of each of these errors
is program-error.
The extent of the returned environment is the same as the extent of the
argument environment env. The result might share structure with env but env is
not modified.
While an environment argument received by an *evalhook* function is permitted
to be used as the environment argument to augment-environment, the consequences
are undefined if an attempt is made to use the result of augment-environment as
the environment argument for evalhook. The environment returned by
augment-environment can be used only for syntactic analysis, that is, as an
argument to the functions defined in this section and functions such as
macroexpand.
[Macro]
define-declaration decl-name lambda-list {form}*
This macro defines a handler for the named declaration. It is the mechanism by
which augment-environment is extended to support additional declaration
specifiers. The function defined by this macro will be called with two
arguments, a declaration specifier whose car is decl-name and the env argument
to augment-environment. This function must return two values. The first value
must be one of the following keywords:
:variable
The declaration applies to variable bindings.
:function
The declaration applies to function bindings.
:declare
The declaration does not apply to bindings.
If the first value is :variable or :function then the second value must be a
list, the elements of which are lists of the form (binding-name key value). If
the corresponding information function (either variable-information or
function-information) is applied to the binding-name and the augmented
environment, the a-list returned by the information function as its third value
will contain the value under the specified key.
If the first value is :declare, the second value must be a cons of the form
(key . value). The function declaration-information will return value when
applied to the key and the augmented environment.
define-declaration causes decl-name to be proclaimed to be a declaration; it is
as if its expansion included a call (proclaim '(declaration decl-name)). As is
the case with standard declaration specifiers, the evaluator and compiler are
permitted, but not required, to add information about declaration specifiers
defined with define-declaration to the macro expansion and *evalhook*
environments.
The consequences are undefined if decl-name is a symbol that can appear as the
car of any standard declaration specifier.
The consequences are also undefined if the return value from a declaration
handler defined with define-declaration includes a key name that is used by the
corresponding accessor to return information about any standard declaration
specifier. (For example, if the first return value from the handler is
:variable, the second return value may not use the symbols dynamic-extent,
ignore, or type as key names.)
The define-declaration macro does not have any special compile-time side
effects (see section 25.1).
[Function]
parse-macro name lambda-list body &optional env
This function is used to process a macro definition in the same way as defmacro
and macrolet. It returns a lambda-expression that accepts two arguments, a form
and an environment. The name, lambda-list, and body arguments correspond to the
parts of a defmacro or macrolet definition.
The lambda-list argument may include &environment and &whole and may include
destructuring. The name argument is used to enclose the body in an implicit
block and might also be used for implementation-dependent purposes (such as
including the name of the macro in error messages if the form does not match
the lambda-list).
[Function]
enclose lambda-expression &optional env
This function returns an object of type function that is equivalent to what
would be obtained by evaluating `(function ,lambda-expression) in a syntactic
environment env. The lambda-expression is permitted to reference only the parts
of the environment argument env that are relevant only to syntactic processing,
specifically declarations and the definitions of macros and symbol macros. The
consequences are undefined if the lambda-expression contains any references to
variable or function bindings that are lexically visible in env, any go to a
tag that is lexically visible in env, or any return-from mentioning a block
name that is lexically visible in env.
[change_end]
-------------------------------------------------------------------------------